.\" $Id: catman.8,v 1.15 2025/07/13 14:15:26 schwarze Exp $
.\"
.\" Copyright (c) 2017, 2025 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: July 13 2025 $
.Dt CATMAN 8
.Os
.Sh NAME
.Nm catman
.Nd format all manual pages below a directory
.Sh SYNOPSIS
.Nm catman
.Op Fl I Cm os Ns = Ns Ar name
.Op Fl T Ar output
.Ar srcdir dstdir
.Sh DESCRIPTION
The
.Nm
utility assumes that all files below
.Ar srcdir
are manual pages in
.Xr mdoc 7
and
.Xr man 7
format and formats all of them, storing the formatted versions in
the same relative paths below
.Ar dstdir .
Unless they already exist,
.Ar dstdir
itself and any required subdirectories are created.
Existing files are not explicitly deleted, but possibly overwritten.
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl I Cm os Ns = Ns Ar name
Override the default operating system
.Ar name
for the
.Xr mdoc 7
.Ic \&Os
and for the
.Xr man 7
.Ic TH
macro.
.It Fl T Ar output
Output format.
The
.Ar output
argument can be
.Cm ascii ,
.Cm utf8 ,
or
.Cm html ;
see
.Xr mandoc 1 .
In
.Cm html
output mode, the
.Cm fragment
output option is implied.
Other output options are not supported.
.It Fl v
Verbose mode, printing additional information to standard error output.
Specifying this once prints a summary about the number of files
and directories processed at the end of the iteration.
Specifying it twice additionally prints debugging information
about the backchannel from
.Xr mandocd 8
to
.Nm
that is used to limit the number of files in flight at any given time.
For details, see
.Sx DIAGNOSTICS .
.El
.Sh IMPLEMENTATION NOTES
Since this version avoids
.Xr fork 2
and
.Xr exec 3
overhead and uses the much faster
.Sy mandoc
parsers and formatters rather than
.Sy groff ,
it may be about one order of magnitude faster than other
.Nm
implementations.
.Sh EXIT STATUS
.Ex -std
.Pp
Failures while trying to open individual manual pages for reading,
to save individual formatted files to the file system,
or even to read or create subdirectories do not cause
.Nm
to return an error exit status.
In such cases,
.Nm
simply continues with the next file or subdirectory.
.Sh DIAGNOSTICS
Some fatal errors cause
.Nm
to exit before the iteration over input files is even started:
.Bl -tag -width Ds -offset indent
.It unknown option \-\- Ar option
An invalid option was passed on the command line.
.It missing arguments: srcdir and dstdir
No argument was provided.
Both
.Ar srcdir
and
.Ar dstdir
are mandatory.
.It missing argument: dstdir
Only one argument was provided.
The second argument,
.Ar dstdir ,
is mandatory, too.
.It too many arguments: Ar third argument
Three or more arguments were provided, but only two are supported.
.It Sy socketpair : Ar reason
The sockets needed for communication with
.Xr mandocd 8
could not be created, for example due to file descriptor or memory exhaustion.
.It Sy fork : Ar reason
The new process needed to run
.Xr mandocd 8
could not be created, for example due to process table exhaustion
or system resource limits.
.It Sy exec Ns Po Sy mandocd Pc : Ar reason
The
.Xr mandocd 8
child program could not be started, for example because it is not in the
.Ev PATH
or has no execute permission.
.It Sy mkdir No destination Ar dstdir : reason
The
.Ar dstdir
does not exist and could not be created, for example because
the parent directory does not exist or permission is denied.
.It Sy open No destination Ar dstdir : reason
The
.Ar dstdir
could not be opened for reading, for example because
it is not a directory or permission is denied.
.It Sy chdir No to source Ar srcdir : reason
The current working directory could not be changed to
.Ar srcdir ,
for example because it does not exist, it is not a directory,
or permission is denied.
.It Sy fts_open : Ar reason
Starting the iteration was attempted but failed,
for example due to memory exhaustion.
.El
.Pp
Some fatal errors cause the iteration over input files to be aborted
prematurely:
.Bl -tag -width Ds -offset indent
.It FATAL: Sy fts_read : Ar reason
A call to
.Xr fts_read 3
returned
.Dv NULL ,
meaning that the iteration failed before being complete.
.It FATAL: mandocd child died: got Ar SIGNAME
This message appears if
.Nm
gets the
.Dv SIGCHLD
or
.Dv SIGPIPE
signal, most likely due to a fatal bug in
.Xr mandocd 8 .
.It FATAL: Sy sendmsg : Ar reason
The file descriptors needed to process one of the manual pages
could not be sent to
.Xr mandocd 8 ,
for example because
.Xr mandocd 8
could not be started or died unexpectedly.
.It FATAL: Sy recv : Ar reason
Trying to read a reply message from
.Xr mandocd 8
failed, most likely because
.Xr mandocd 8
unexpectedly died or closed the socket.
.It FATAL: signal Ar SIGNAME
This message appears if
.Nm
gets a
.Dv SIGHUP ,
.Dv SIGINT ,
or
.Dv SIGTERM
signal, for example because the user deliberately killed it.
.El
.Pp
Some non-fatal errors cause a single subdirectory to be skipped.
The iteration is not aborted but continues with the next subdirectory,
and the exit status is unaffected:
.Bl -tag -width Ds -offset indent
.It directory Ar subdirectory No unreadable : Ar reason
A directory below
.Ar srcdir
could not be read and is skipped.
.It directory Ar subdirectory No causes cycle
A directory below
.Ar srcdir
is skipped because it would cause cyclic processing.
.It Sy mkdirat Ar subdirectory : reason
A required directory below
.Ar dstdir
does not exist and could not be created.
The corresponding subdirectory below
.Ar srcdir
is skipped.
.El
.Pp
Some non-fatal errors cause a single source file to be skipped.
The iteration is not aborted but continues with the next file,
and the exit status is unaffected:
.Bl -tag -width Ds -offset indent
.It file Ar filename : reason
The function
.Xr fts_read 3
reported a non-fatal error with respect to
.Ar filename .
.It file Ar filename : No not a regular file
For example, it might be a symbolic link or a device file.
.It Sy open Ar filename No for reading : Ar reason
A file below
.Ar srcdir
could not be read, for example due to permission problems.
.It Sy openat Ar filename No for writing : Ar reason
A file below
.Ar dstdir
could not be created or truncated, for example due to permission problems.
.El
.Pp
If errors occur, the applicable summary messages appear
after the end of the iteration:
.Pp
.Bl -tag -width Ds -offset indent -compact
.It skipped Ar number No directories due to errors
.It skipped Ar number No files due to errors
.It processing aborted due to fatal error
.El
.Pp
If the
.Fl v
flag is specified, the following summary message also appears:
.Bl -tag -width Ds -offset indent
.It processed Ar nfiles No files in Ar ndirs No directories
A file is counted if it could be opened for reading and the
corresponding output file could be opened for writing;
this does not necessarily mean that it is a useful manual page.
A directory is counted if it could be opened for reading and the
corresponding output directory existed or could be created;
this does not necessarily mean that any files could be
processed inside.
.El
.Pp
If the
.Fl v
flag is specified twice, the following messages also appear:
.Bl -tag -width Ds -offset indent
.It allowing up to Ar number No files in flight
This is printed at the beginning of the iteration,
showing the maximum number of files that
.Nm
allows to be in flight at any given time.
.It files in flight: Ar old No \- Ar decrement No = Ar new
This message is printed when
.Nm
learns about
.Xr mandocd 8
accepting more than one file at the same time.
The three numbers printed are the old number of files in flight,
the amount this number is being reduced, and the resulting
new number of files in flight.
.It waiting for Ar number No files in flight
This message is printed at the end of the iteration, after
.Nm
has submitted all files to
.Xr mandocd 8
that it intends to.
THe message informs about the number of files still in flight
at this point.
The
.Nm
program then waits until
.Xr mandocd 8
has accepted them all or until an error occurs.
.El
.Sh SEE ALSO
.Xr mandoc 1 ,
.Xr mandocd 8
.Sh HISTORY
A
.Nm
utility first appeared in
.Fx 1.0 .
Other, incompatible implementations appeared in
.Nx 1.0
and in
.Sy man-db No 2.2 .
.Pp
This version appeared in version 1.14.1 of the
.Sy mandoc
toolkit.
.Sh AUTHORS
.An -nosplit
The first
.Nm
implementation was a short shell script by
.An Christoph Robitschko
in July 1993.
.Pp
The
.Nx
implementations were written by
.An J. T. Conklin Aq Mt jtc@netbsd.org
in 1993,
.An Christian E. Hopps Aq Mt chopps@netbsd.org
in 1994,
and
.An Dante Profeta Aq Mt dante@netbsd.org
in 1999; the
.Sy man-db
implementation by
.An Graeme W. Wilford
in 1994; and the
.Fx
implementations by
.An Wolfram Schneider Aq Mt wosch@freebsd.org
in 1995 and
.An John Rochester Aq Mt john@jrochester.org
in 2002.
.Pp
The concept of the present version was designed and implemented by
.An Michael Stapelberg Aq Mt stapelberg@debian.org
in 2017.
Option and argument handling and directory iteration was added by
.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
.Sh CAVEATS
All versions of
.Nm
are incompatible with each other because each caters to the needs
of a specific operating system, for example regarding directory
structures and file naming conventions.
.Pp
This version is more flexible than the others in so far as it does
not assume any particular directory structure or naming convention.
That flexibility comes at the price of not being able to change the
names and relative paths of the source files when reusing them to
store the formatted files, of not supporting any configuration file
formats or environment variables, and of being unable to scan for
and remove junk files in
.Ar dstdir .
.Pp
Currently,
.Nm
always reformats each page, even if the formatted version is newer
than the source version.
